<?php
/**
 * Created by PhpStorm
 * User: whh
 * Date: 2022/12/6
 * Time: 10:08
 */

namespace app\common\command;

use app\common\model\Novel;
use app\common\model\NovelChapter;
use app\common\model\NovelMpParty;
use app\backstage\server\UploadServer;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\Db;
use think\facade\Env;

/**
 * 上传硬盘文件到数据库
 * Class UploadHardDiskBooks
 * @package app\common\command
 */
class UploadHardDiskBooks extends Command
{
    protected function configure()
    {
        $this->setName('uploadBook')
            ->addArgument('action', Argument::OPTIONAL, "方法名称")
            ->addOption('dir', null, Option::VALUE_REQUIRED, '硬盘书籍文件路径')
            ->setDescription('上传硬盘小说文件到数据库');
    }

    protected function execute(Input $input, Output $output)
    {
        $action = $input->getArgument('action');
        if (method_exists($this, $action)) {
            if (strtolower($action) == 'upload') {
                $dir = "/public/Book/";
                if ($input->hasOption('dir')) {
                    $dir = $input->getOption('dir');
                }
                $this->upload($dir);
            } else {
                $this->$action();
            }
        } else {
            /** @var TYPE_NAME $output */
            die($output->writeln("not method: " . __CLASS__ . "->" . $action));
        }
        $output->writeln(__CLASS__ . " console end;");
    }


    /**
     * 上传
     * @param $dir
     */
    public function upload($dir)
    {
        $absolute_root_path = Env::get('root_path');
        $dirs_parent = $this->getSubDirs($absolute_root_path . $dir);
        $dirs_parent = array_reverse($dirs_parent);
        foreach ($dirs_parent as $v) {
            if (!is_dir($dir . trim($v))) {
                $bookname = str_replace('.txt', '', $v);
                $record = Novel::getByTitle($bookname);
                $fileRes = $this->getContentByFile($dir . $v);
                if ($fileRes['code'] > 0) {
                    continue;
                }
                if (empty($record)) {
                    $save = [
                        'title' => $bookname,
                        'origin_title' => $bookname,
                        'author' => $fileRes['data']['info']['author'],
                        'cover' => $fileRes['data']['info']['cover'],
                        'brief' => $fileRes['data']['info']['brief'],
                        'update_status' => $fileRes['data']['info']['update_status'],
                        'in_shelf' => 0,
                        'scale' => 'C',//默认C级别
                    ];
                    $nid = Novel::insertGetId($save);
                    NovelMpParty::insert([
                        'novel_id' => $nid,
                        'party_code' => 'hd',
                        'party_novel_id' => $nid,
                    ]);
                } else {
                    $nid = $record->id;
                }
                $fastPayChapter = $fileRes['data']['info']['fastPayChapter'];
                $add_res = $this->batchAddChapter($fileRes['data']['chapters'], $fastPayChapter, $nid, 0);
                $up['number_words'] = $add_res['word_counts'];
                $up['chapter_up_time'] = date("Y-m-d H:i:s");
                Novel::where("id", $nid)->update($up);
                echo $bookname . "推送完成" . PHP_EOL;
            }
        }
    }


    /**
     * 章节批量写入
     * @param $chapters
     * @param $charging_section
     * @param $nid
     * @param int $sequel
     * @return array
     * @Author: whh
     */
    private function batchAddChapter($chapters, $charging_section, $nid, $sequel = 0)
    {

        if ($sequel == 1) {
            $word_counts = $this->getNovelNumber($nid);
            $i = $this->getMaxChapnum($nid);
        } else {
            $word_counts = 0;
            $i = 0;
        }
        foreach ($chapters as $v) {
            $i++;
            $where = [];
            $where[] = ['novel_id', '=', $nid];
            $where[] = ['chapter_no', '=', $i];
            $chapter = NovelChapter::where($where)->find();
            if (!$chapter) {
                $chapterModel = new NovelChapter;
                $chapterModel->novel_id = $nid;
                $chapterModel->name = $v['cname'];
                $chapterModel->chapter_no = $i;
                $chapterModel->is_pay = $i >= $charging_section ? 1 : 0;
                $chapterModel->words = clearHtmlGetNum($v['content']);;
                $chapterModel->save();
                $word_counts = $word_counts + $chapterModel->words;
                $chapterModel->setContent($v['content'], $nid, $i);
            }
        }

        return ['code' => 0, 'msg' => '章节添加成功', 'word_counts' => $word_counts];
    }


    /*获取最大章节序号*/
    private function getMaxChapnum($nid)
    {
        $chapter_no = NovelChapter::where('novel_id', $nid)->order("chapter_no desc")->value('chapter_no');
        return $chapter_no ? $chapter_no : 0;
    }

    /*获取书籍字数*/
    private function getNovelNumber($nid)
    {
        $number_words = NovelChapter::where('novel_id', $nid)->value('number_words');
        return $number_words ? $number_words : 0;
    }


    /**
     * 读取章节内容txt
     * @param $txt_path
     * @return array
     * @Author: whh
     */
    private function getContentByFile($txt_path)
    {

        if (strlen($txt_path) < 1) {
            return ['code' => 0, 'msg' => '章节内容txt未上传', 'data' => []];
        }

        $max_len = 75;
        $pregArray = array();

        //规则  【第一百五十四章 xxx】  【第001章 xxx】
        $preg['rule'] = '#(.*?)第[\s\S]{1,30}章(.*?)#ims';
        $preg['maxlen'] = 90;
        $pregArray[] = $preg;
        //规则  【001 xxx】
        /*$preg['rule']   = '#^\d{1,6}(.+?)$#';
        $preg['maxlen'] = 70;
        $pregArray[]    = $preg;*/
        //规则  【001】
        /*$preg['rule']   = '#^\d{1,6}$#';
        $preg['maxlen'] = 10;
        $pregArray[]    = $preg;*/
        //增加规则  如果存在【###】  或者 【####】 就认为是标题

        $root_path = Env::get('root_path');
        $file_path = $root_path . $txt_path;

        $file = fopen($file_path, "rb");

        if (!$file) {
            return ['code' => 1, 'msg' => '上传失败，请确定上传文件格式为utf-8格式！'];
        }

        $chapterlist = array();
        $chapter = array();
        $isbegin = false;
        $content = $cname = $lastcname = $getcname = $lastgetcname = $author = $cover = $brief = '';
        $update_status = 0;
        $fastPayChapter = 7;
        while (!feof($file)) {

            $line = fgets($file);
            $line = str_replace('(', '（', $line);
            $line = str_replace(')', '）', $line);

            if (!$isbegin) {

                if (!$this->check_is_Utf8($line)) {
                    return ['code' => 2, 'msg' => '文件格式不对，请使用UTF8格式上传!'];
                }
            }

            $ruleline = preg_replace(array('/　　/', '/　/', '/　/'), '', trim($line));

            foreach ($pregArray as $v) {
                $res = preg_match($v['rule'], $ruleline, $match);
                $max_len = $v['maxlen'];
                if ($res) {
                    break;
                }
            }

            //增加规则  如果存在【###】  或者 【####】 而且在一开始的位置就认为是标题
            $isTitle = false;
            $getjh1 = stripos($ruleline, '####');
            $getjh2 = stripos($ruleline, '###');

            if (strstr($ruleline, '####') && $getjh1 == 0) {
                $isTitle = true;
            } else if (strstr($ruleline, '###') && $getjh2 == 0) {
                $isTitle = true;
            } else if (strstr($ruleline, '#')) {
                //如果存在#字符 则人为判断该行不是标题，需要手动设置
                $res = false;
            }

            if (strstr($ruleline, '作者:')) {
                $author = trim(substr($line, strripos($line, "作者:") + 7));
            }
            if (strstr($ruleline, '更新进度:')) {
                $str = trim(substr($line, strripos($line, "更新进度:") + 13));
                if ($str == '完本') {
                    $update_status = 1;
                }
            }
            if (strstr($ruleline, '开始收费章节:')) {
                $str = trim(substr($line, strripos($line, "开始收费章节:") + 19));
                if ($str) {
                    $fastPayChapter = $str;
                }
            }
            if (strstr($ruleline, '简介:')) {
                $brief = trim(substr($line, strripos($line, "简介:") + 7));
            }
            if (strstr($ruleline, '封面:')) {
                $imgUrl = trim(substr($line, strripos($line, "封面:") + 7));
                $addTime = date("Ymd", time());
                $path = Env::get('ROOT_PATH') . 'uploads/' . $addTime . "/";
                if (!file_exists($path)) {
                    mkdir($path, 0777);
                }
                $server = new UploadServer();
                $filename = md5(rand(1, 99999999)) . $server->getExtension($imgUrl);
                $cover = $server->downLoadPic($imgUrl, $path, $filename);
            }

            if ($isTitle || ($res && strlen(trim($ruleline)) < $max_len)) {
                $lastcname = $cname;
                $lastgetcname = $getcname;

                $cname = str_replace('####', '', $ruleline);
                $cname = str_replace('###', '', $cname);
                $getcname = $cname;
                if ($isbegin) {
                    $chapter['cname'] = $lastcname;
                    $chapter['getcname'] = $lastgetcname;
                    $chapter['content'] = $content;
                    $chapterlist[] = $chapter;
                    $content = '';
                }

                $isbegin = true;

            } else {
                if ($isbegin) {
                    $content .= $line . "\n";
                }
            }
        }
        $chapter['cname'] = $cname;
        $chapter['getcname'] = $getcname;
        $chapter['content'] = $content;
        $chapterlist[] = $chapter;

        fclose($file);

        unlink($file_path);
        return ['code' => 0, 'msg' => 'ok', 'data' => [
            'info' => [
                'author' => $author,
                'cover' => $cover,
                'brief' => $brief,
                'update_status' => $update_status,
                'fastPayChapter' => $fastPayChapter,
            ],
            'chapters' => $chapterlist
        ]];
    }


    /**
     * 获取下属文件数组
     * @param $dir
     * @return array
     */
    private function getSubDirs($dir)
    {
        $subdirs = array();

        if (!$dh = opendir($dir)) {
            return $subdirs;
        }
        $i = 0;
        while ($f = readdir($dh)) {
            if ($f == '.' || $f == '..') {
                continue;
            }
            //如果只要子目录名, path = $f;
            //$path = $dir.'/'.$f;
            $path = $f;
            $subdirs[$i] = $path;
            $i++;
        }
        return $subdirs;
    }


    /**
     * @param $str
     * @return bool
     * @Author: whh
     */
    function check_is_Utf8($str)
    {
        $charset = mb_detect_encoding($str, array('UTF-8', 'GBK', 'GB2312', 'BIG-5'));
        $charset = strtolower($charset);
        if ($charset != 'utf-8') {
            return false;
        }
        return true;
    }


    /**
     * @param $content
     * @param $start
     * @param $end
     * @return string
     * @Author: whh
     */
    function formatChapterContent($content, $start, $end)
    {
        $content_new = '';

        if (strlen($content) < 1) {
            return $content_new;
        }

        $content = str_replace("<p>", "\r\n", $content);
        $content = str_replace("</p>", "\r\n", $content);

        $list = explode("\r\n", $content);

        $list_new = '';
        foreach ($list as $k => $v) {

            if ($this->trim_space($v)) {
                $list_new .= $start . $this->trim_space($v) . $end;
            }
        }

        return $list_new;

    }

    function trim_space($content)
    {
        $content = trim(strip_tags($content));
        $content = preg_replace("/^" . chr(194) . chr(160) . "+/", "", $content);
        $content = preg_replace('# #', '', $content);
        $content = $this->removeIllegalChar($content);
        $search = array(" ", "　", "\t", "\n", "\r", "&nbsp;");
        $replace = array("", "", "", "", "", "");

        return str_replace($search, $replace, $content);
    }

    function removeIllegalChar($content)
    {
        if (is_string($content)) {

            $content = preg_replace("/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/", "", $content);

        } else if (is_array($content)) {

            foreach ($content as $k => $v) {
                $content[$k] = $this->removeIllegalChar($v);
            }

        }

        return $content;
    }
}